﻿using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Web.Security;

namespace SiteLib.SiteMembership
{
	public class AccountModels
	{
		#region Models
		[PropertiesMustMatch("NewPassword", "ConfirmPassword", ErrorMessage = "The new password and confirmation password do not match.")]
		public class ChangePasswordModel
		{
			[Required]
			[DataType(DataType.Password)]
			[DisplayName("Current password")]
			public string OldPassword { get; set; }

			[Required]
			[ValidatePasswordLength]
			[DataType(DataType.Password)]
			[DisplayName("New password")]
			public string NewPassword { get; set; }

			[Required]
			[DataType(DataType.Password)]
			[DisplayName("Confirm new password")]
			public string ConfirmPassword { get; set; }
		}

		public class LogOnModel
		{
			[Required]
			[DisplayName("User name")]
			public string UserName { get; set; }

			[Required]
			[DataType(DataType.Password)]
			[DisplayName("Password")]
			public string Password { get; set; }

			[DisplayName("Remember me?")]
			public bool RememberMe { get; set; }
		}

		[PropertiesMustMatch("Password", "ConfirmPassword", ErrorMessage = "The password and confirmation password do not match.")]
		public class RegisterModel
		{
			[Required]
			[DisplayName("User name")]
			public string UserName { get; set; }

			[Required]
			[DataType(DataType.EmailAddress)]
			[DisplayName("Email address")]
			public string Email { get; set; }

			[Required]
			[ValidatePasswordLength]
			[DataType(DataType.Password)]
			[DisplayName("Password")]
			public string Password { get; set; }

			[Required]
			[DataType(DataType.Password)]
			[DisplayName("Confirm password")]
			public string ConfirmPassword { get; set; }
		}
		#endregion

		#region Validation
		public static class AccountValidation
		{
			public static string ErrorCodeToString(MembershipCreateStatus createStatus)
			{
				// See http://go.microsoft.com/fwlink/?LinkID=177550 for
				// a full list of status codes.
				switch (createStatus)
				{
					case MembershipCreateStatus.DuplicateUserName:
						return "Username already exists. Please enter a different user name.";

					case MembershipCreateStatus.DuplicateEmail:
						return "A username for that e-mail address already exists. Please enter a different e-mail address.";

					case MembershipCreateStatus.InvalidPassword:
						return "The password provided is invalid. Please enter a valid password value.";

					case MembershipCreateStatus.InvalidEmail:
						return "The e-mail address provided is invalid. Please check the value and try again.";

					case MembershipCreateStatus.InvalidAnswer:
						return "The password retrieval answer provided is invalid. Please check the value and try again.";

					case MembershipCreateStatus.InvalidQuestion:
						return "The password retrieval question provided is invalid. Please check the value and try again.";

					case MembershipCreateStatus.InvalidUserName:
						return "The user name provided is invalid. Please check the value and try again.";

					case MembershipCreateStatus.ProviderError:
						return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

					case MembershipCreateStatus.UserRejected:
						return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

					default:
						return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
				}
			}
		}

		[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
		public sealed class PropertiesMustMatchAttribute : ValidationAttribute
		{
			private const string DefaultErrorMessage = "'{0}' and '{1}' do not match.";
			private readonly object _typeId = new object();

			public PropertiesMustMatchAttribute(string originalProperty, string confirmProperty)
				: base(DefaultErrorMessage)
			{
				OriginalProperty = originalProperty;
				ConfirmProperty = confirmProperty;
			}

			public string ConfirmProperty { get; private set; }
			public string OriginalProperty { get; private set; }

			public override object TypeId
			{
				get
				{
					return _typeId;
				}
			}

			public override string FormatErrorMessage(string name)
			{
				return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
					OriginalProperty, ConfirmProperty);
			}

			public override bool IsValid(object value)
			{
				PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
				object originalValue = properties.Find(OriginalProperty, true /* ignoreCase */).GetValue(value);
				object confirmValue = properties.Find(ConfirmProperty, true /* ignoreCase */).GetValue(value);
				return Equals(originalValue, confirmValue);
			}
		}

		[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
		public sealed class ValidatePasswordLengthAttribute : ValidationAttribute
		{
			private const string _defaultErrorMessage = "'{0}' must be at least {1} characters long.";
			private readonly int _minCharacters = Membership.Provider.MinRequiredPasswordLength;

			public ValidatePasswordLengthAttribute()
				: base(_defaultErrorMessage)
			{
			}

			public override string FormatErrorMessage(string name)
			{
				return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
					name, _minCharacters);
			}

			public override bool IsValid(object value)
			{
				string valueAsString = value as string;
				return (valueAsString != null && valueAsString.Length >= _minCharacters);
			}
		}
		#endregion
	}
}